package su.msk.jet.team01.chatik.server.data;

import su.msk.jet.team01.chatik.server.db.DatabaseAdapter;
import su.msk.jet.team01.chatik.server.exception.ClientNotFoundException;
import su.msk.jet.team01.chatik.server.exception.NameInUseException;

import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public final class DataManager {
	private static Map<String, Client> clients = new HashMap<String, Client>();
	private static Map<String, Room> rooms = new HashMap<String, Room>();
	private static Room defaultRoom = createRoom("All");

	private static DatabaseAdapter database = DatabaseAdapter.get();
	
	private static Logger logger = LoggerFactory.getLogger(DataManager.class);
	
	public static final String SQL_QUERY_SELECT_USER_ID = "SELECT id FROM users WHERE name=?";

	public static int getDatabaseID(final String name) {
		List<Map<String, Object>> res;

		if (name.isEmpty()) {
			return -1;
		}
		
		try {
			res = database.executeQuery(SQL_QUERY_SELECT_USER_ID, name);
			if (res.size() == 0) {
				database.execute("INSERT INTO users (name) VALUES (?)", name);
				res = database.executeQuery(SQL_QUERY_SELECT_USER_ID,
						name);
			}
			return (Integer) res.get(0).get("ID");
		} catch (SQLException ex) {
			logger.error(ex.getMessage(), ex);
			return -1;
		}
	}

	public static void addClient(final Client client) {
		synchronized (clients) {
			clients.put(client.getName(), client);
		}
	}

	public static void changeClientName(final Client client,
			final String newName) throws NameInUseException {
		synchronized (clients) {
			String currentName = client.getName();

			if (clients.get(newName) != null) {
				throw new NameInUseException("Client " + currentName
						+ " tried to change his name to already used name "
						+ newName);
			}
			if (!currentName.isEmpty()) {
				removeClient(client);
			}
			client.setName(newName);
			addClient(client);
		}
	}

	public static Client findClient(final String name)
			throws ClientNotFoundException {
		Client client;

		synchronized (clients) {
			client = clients.get(name);

			if (client == null) {
				throw new ClientNotFoundException("User " + name + " not found");
			}
			return client;
		}
	}

	public static Map<String, Client> getClients() {
		synchronized (clients) {
			return new HashMap<String, Client>(clients);
		}
	}

	public static Room getDefaultRoom() {
		return defaultRoom;
	}

	public static Room getRoom(final String name) {
		Room room;

		synchronized (rooms) {
			room = rooms.get(name);

			if (room == null) {
				room = createRoom(name);
			}
			return room;
		}
	}

	public static Map<String, Room> getRooms() {
		synchronized (rooms) {
			return new HashMap<String, Room>(rooms);
		}
	}

	public static void removeClient(final Client client) {
		synchronized (clients) {
			clients.remove(client.getName());
		}
	}

	public static void removeRoom(final String name) {
		Room room;

		synchronized (rooms) {
			room = rooms.get(name);
			if (room != null && room.getClients().size() == 0) {
				rooms.remove(room.getName());
			}
		}
	}

	private static Room createRoom(final String name) {
		Room room;

		synchronized (rooms) {
			room = new Room(name);
			rooms.put(name, room);
		}
		return room;
	}

	private DataManager() {

	}
}
